﻿namespace MsForgeReboot.Services {
    #region Usings

    using System.Collections.Generic;
    using System.Linq;
    using MsForgeReboot.Framework.Entities;
    using MsForgeReboot.Framework.Interfaces;
    using MsForgeReboot.Framework.ViewModels;

    #endregion

    /// <summary>
    ///   The cms service.
    /// </summary>
    public class CmsService : ICmsService {
        #region Fields

        /// <summary>
        ///   The _context.
        /// </summary>
        private readonly MsForgeContext _context;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="CmsService"/> class.
        /// </summary>
        /// <param name="context">
        /// The context. 
        /// </param>
        public CmsService(MsForgeContext context) {
            this._context = context;
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Deletes a Section
        /// </summary>
        /// <param name="id">
        /// The ID of the Section to be deleted. 
        /// </param>
        public void Delete(int id) {
            this._context.Sections.Remove(this._context.Sections.First(s => s.Id == id));
            this._context.SaveChanges();
        }

        /// <summary>
        /// Deletes a Page.
        /// </summary>
        /// <param name="pageID">
        /// The ID of the Page to be deleted. 
        /// </param>
        public void DeletePage(int pageID) {
            this._context.Pages.Remove(this._context.Pages.Single(p => p.Id == pageID));
            this._context.SaveChanges();
        }

        /// <summary>
        /// The get page by url title.
        /// </summary>
        /// <param name="urlTitle">
        /// The url title.
        /// </param>
        /// <returns>
        /// The <see cref="Page"/>.
        /// </returns>
        public Page GetPageByUrlPointer(string urlTitle) {
            return this._context.Pages.SingleOrDefault(p => p.UrlPointer == urlTitle);
        }

        /// <summary>
        /// Return a page for a given Section.
        /// </summary>
        /// <param name="sectionID">
        /// The section id. 
        /// </param>
        /// <returns>
        /// The <see cref="Page">Page</see> for that Section. 
        /// </returns>
        public Page GetPageForSection(int sectionID) {
            return this._context.Sections.SingleOrDefault(s => s.Id == sectionID).Page;
        }

        /// <summary>
        ///   Get all of the Sections ordered by their order (ASC).
        /// </summary>
        /// <returns> The ordered list of Sections. </returns>
        public IList<SectionListViewModel> GetSections() {
            //return this._context.Sections.OrderBy(s => s.Order).ToList();
            var sections = this._context.Sections.OrderBy(s => s.Order).Select(s => new SectionListViewModel {
                ID = s.Id,
                Order = s.Order,
                Title = s.Title,
                Url = s.UrlPointer,
                HasPage = (s.Page != null) ? true : false
            }).ToList();
            return sections;
        }

        /// <summary>
        /// The get single section.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <returns>
        /// The <see cref="Section"/>.
        /// </returns>
        public Section GetSingleSection(int id) {
            return this._context.Sections.Single(s => s.Id == id);
        }

        /// <summary>
        /// Saves or edits a Section.
        /// </summary>
        /// <param name="section">
        /// A Section to be added or changed in the database. 
        /// </param>
        public void Save(Section section) {
            if (section.Id == 0) {
                this._context.Sections.Add(section);
            }
            else {
                var originalSection = this._context.Sections.Single(s => s.Id == section.Id);
                originalSection.Order = section.Order;
                originalSection.Title = section.Title;
                originalSection.UrlPointer = section.UrlPointer;
            }

            // Reorder the sections
            // The "algorithm" is dead simple: take those that have an equal or higher order
            // Then loop to increase them.
            var sections = this._context.Sections.Where(s => s.Order >= section.Order);
            if (sections.Count() > 0) {
                int i = section.Order + 1;
                foreach (var item in sections) {
                    item.Order = i;
                    i++;
                }
            }

            this._context.SaveChanges();
        }


        /// <summary>
        /// Saves or edits a Page.
        /// </summary>
        /// <param name="item">
        /// A Page to be added or changed in the database. 
        /// </param>
        /// 
        // HACK: a workaround to be able to unblock myself until the real solution is found
        public void SavePage(PageAddViewModel item) {
            Section section = this._context.Sections.Single(s => s.Id == item.SectionID);
            item.UrlPointer = item.UrlPointer.Replace(" ", "-").Substring(0, (item.UrlPointer.Length <= 255) ? item.UrlPointer.Length : 255);
            if (item.Id == 0) {
                Page page = new Page { Body = item.Body, Title = item.Title, Published = item.Published, Author = item.Author, UrlPointer = item.UrlPointer };
                this._context.Pages.Add(page);
                // Update the section
                section.Page = page;
            }
            else {
                var dbPage = this._context.Pages.First(p => p.Id == item.Id);
                dbPage.Body = item.Body;
                dbPage.Title = item.Title;
                dbPage.UrlPointer = item.UrlPointer;
            }

            this._context.SaveChanges();
        }

        #endregion
    }
}